//
// Created by xinhua on 2021/10/23.
//

#include "MainGui.h"

MainGui::MainGui() {

}

MainGui::~MainGui() {

}

void MainGui::setObject3D(Object3D *_object3D) {
    scene = dynamic_cast<Scene *> (_object3D);
}

void MainGui::onRender(float elapsedTime, Matrix4x4 proj, Matrix4x4 view, Matrix4x4 pworld) {
    if(!bVisible) return;

    //开启
    static bool *p_open = &bVisible;

    //显示主菜单栏
    ShowAppMainMenuBar();

    //显示帧率信息
    showFramInfo(p_open);

    //显示列表信息
    showItemDetail(scene, p_open);
}

/**
 * 显示菜单栏
 */
void MainGui::ShowAppMainMenuBar()
{
    if (ImGui::BeginMainMenuBar())
    {
        if (ImGui::BeginMenu("File"))
        {
            ShowMenuFile();
            ImGui::EndMenu();
        }
        if (ImGui::BeginMenu("Edit"))
        {
            if (ImGui::MenuItem("Undo", "CTRL+Z")) {}
            if (ImGui::MenuItem("Redo", "CTRL+Y", false, false)) {}  // Disabled item
            ImGui::Separator();
            if (ImGui::MenuItem("Cut", "CTRL+X")) {}
            if (ImGui::MenuItem("Copy", "CTRL+C")) {}
            if (ImGui::MenuItem("Paste", "CTRL+V")) {}
            ImGui::EndMenu();
        }
        if (ImGui::BeginMenu("Add"))
        {
            if (ImGui::BeginMenu("3D Object"))
            {
                if(ImGui::MenuItem("3D Triangle")) {
                    float x = rand() % 10;
                    float y = rand() % 10;

                    log_info("Add 3D Triangle! todo.");
                }

                if(ImGui::MenuItem("Cube")) {
                    log_info("Add Cube! todo.");
                };
                if(ImGui::MenuItem("Sphere")) {
                    log_info("Add Sphere! todo.");
                };
                ImGui::EndMenu();
            }
            ImGui::Separator();
            if (ImGui::MenuItem("Camera", "SHIFT+C")) {}
            ImGui::EndMenu();
        }
        ImGui::EndMainMenuBar();
    }
}

/**
 * 菜单栏 File
 */
void MainGui::ShowMenuFile()
{
    ImGui::MenuItem("(demo menu)", NULL, false, false);
    if (ImGui::MenuItem("New")) {}
    if (ImGui::MenuItem("Open", "Ctrl+O")) {}
    if (ImGui::BeginMenu("Open Recent"))
    {
        ImGui::MenuItem("fish_hat.c");
        ImGui::MenuItem("fish_hat.inl");
        ImGui::MenuItem("fish_hat.h");
        if (ImGui::BeginMenu("More.."))
        {
            ImGui::MenuItem("Hello");
            ImGui::MenuItem("Sailor");
            if (ImGui::BeginMenu("Recurse.."))
            {
                ShowMenuFile();
                ImGui::EndMenu();
            }
            ImGui::EndMenu();
        }
        ImGui::EndMenu();
    }
    if (ImGui::MenuItem("Save", "Ctrl+S")) {}
    if (ImGui::MenuItem("Save As..")) {}

    ImGui::Separator();
    if (ImGui::BeginMenu("Options"))
    {
        static bool enabled = true;
        ImGui::MenuItem("Enabled", "", &enabled);
        ImGui::BeginChild("child", ImVec2(0, 60), true);
        for (int i = 0; i < 10; i++)
            ImGui::Text("Scrolling Text %d", i);
        ImGui::EndChild();
        static float f = 0.5f;
        static int n = 0;
        ImGui::SliderFloat("Value", &f, 0.0f, 1.0f);
        ImGui::InputFloat("Input", &f, 0.1f);
        ImGui::Combo("Combo", &n, "Yes\0No\0Maybe\0\0");
        ImGui::EndMenu();
    }

    if (ImGui::BeginMenu("Colors"))
    {
        float sz = ImGui::GetTextLineHeight();
        for (int i = 0; i < ImGuiCol_COUNT; i++)
        {
            const char* name = ImGui::GetStyleColorName((ImGuiCol)i);
            ImVec2 p = ImGui::GetCursorScreenPos();
            ImGui::GetWindowDrawList()->AddRectFilled(p, ImVec2(p.x + sz, p.y + sz), ImGui::GetColorU32((ImGuiCol)i));
            ImGui::Dummy(ImVec2(sz, sz));
            ImGui::SameLine();
            ImGui::MenuItem(name);
        }
        ImGui::EndMenu();
    }

    // Here we demonstrate appending again to the "Options" menu (which we already created above)
    // Of course in this demo it is a little bit silly that this function calls BeginMenu("Options") twice.
    // In a real code-base using it would make senses to use this feature from very different code locations.
    if (ImGui::BeginMenu("Options")) // <-- Append!
    {
        static bool b = true;
        ImGui::Checkbox("SomeOption", &b);
        ImGui::EndMenu();
    }

    if (ImGui::BeginMenu("Disabled", false)) // Disabled
    {
        IM_ASSERT(0);
    }
    if (ImGui::MenuItem("Checked", NULL, true)) {}
    if (ImGui::MenuItem("Quit", "Alt+F4")) {}
}

//显示列表信息
void MainGui::showItemDetail(Scene *scene, bool *p_open) const {
    // check
    MAssert::check(scene);
    // get object list
    std::vector<Object3D *> objectList = scene->getChildrenList();

    ImGui::SetNextWindowSize(ImVec2(500, 440), ImGuiCond_FirstUseEver);
    if (ImGui::Begin("Scene: Object Layout", p_open, ImGuiWindowFlags_MenuBar))
    {
        ImGui::Text("Camera<?camera editable?>", scene->getActiveCamera()->name.c_str());
        // Left
        static int selected = 0;
        static int selectedIndex = 0;
        {
            ImGui::BeginChild("Scene", ImVec2(150, 0), true);

            int index = 0;
            for (auto iterator = objectList.begin(); iterator != objectList.end(); ++iterator) {
                Object3D * obj = *iterator;
                if(!MAssert::isNull(obj)){
                    if (ImGui::Selectable(obj->name.c_str(), selected == obj->id)){
                        selected = obj->id;
                        selectedIndex = index;
                    }
                }

                index++;
            }

            ImGui::EndChild();
        }
        ImGui::SameLine();

        // Right
        {
            ImGui::BeginGroup();
            ImGui::BeginChild("Detail", ImVec2(0, -ImGui::GetFrameHeightWithSpacing())); // Leave room for 1 line below us

            Object3D * obj = objectList[selectedIndex];

            if(!MAssert::isNull(obj)) {
                ImGui::Text("Object3D: %s", obj->name.c_str());
                ImGui::Separator();
                if (ImGui::BeginTabBar("##Tabs", ImGuiTabBarFlags_None)) {
                    if (ImGui::BeginTabItem("Info")) {

                        obj->drawUI();

                        Camera *camera = dynamic_cast<Camera*>(obj);
                        if(!MAssert::isNull(camera)){
                            ImGui::Text("Active this camera?");
                            ImGui::SameLine();
                            if(ImGui::Button("active")){
                                scene->setActiveCamera(camera);
                            }
                        }

                        ImGui::EndTabItem();
                    }
                    if (ImGui::BeginTabItem("Material")) {
                        // matrial
                        obj->p_material->drawUI();
                        ImGui::EndTabItem();
                    }
                    ImGui::EndTabBar();
                }
                ImGui::EndChild();
                ImGui::EndGroup();
            }
        }
    }
    ImGui::End();
}

/**
 * 显示帧率信息
 * @param p_open 是否显示
 */
void MainGui::showFramInfo(bool *p_open) const {
    static int corner = 1;//默认右上角
    ImGuiIO& io = ImGui::GetIO();
    ImGuiWindowFlags window_flags = ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoSavedSettings | ImGuiWindowFlags_NoFocusOnAppearing | ImGuiWindowFlags_NoNav;
    if (corner != -1)
    {
        const float PAD = 10.0f;
        const ImGuiViewport* viewport = ImGui::GetMainViewport();
        ImVec2 work_pos = viewport->WorkPos; // Use work area to avoid menu-bar/task-bar, if any!
        ImVec2 work_size = viewport->WorkSize;
        ImVec2 window_pos, window_pos_pivot;
        window_pos.x = (corner & 1) ? (work_pos.x + work_size.x - PAD) : (work_pos.x + PAD);
        window_pos.y = (corner & 2) ? (work_pos.y + work_size.y - PAD) : (work_pos.y + PAD);
        window_pos_pivot.x = (corner & 1) ? 1.0f : 0.0f;
        window_pos_pivot.y = (corner & 2) ? 1.0f : 0.0f;
        ImGui::SetNextWindowPos(window_pos, ImGuiCond_Always, window_pos_pivot);
        window_flags |= ImGuiWindowFlags_NoMove;
    }
    ImGui::SetNextWindowBgAlpha(0.35f); // Transparent background
    if (ImGui::Begin("Frame Info", p_open, window_flags))
    {
        ImGui::Text("(right-click to move.)");
        if (ImGui::IsMousePosValid())
            ImGui::Text("Mouse Position: (%.1f,%.1f)", io.MousePos.x, io.MousePos.y);
        else
            ImGui::Text("Mouse Position: <invalid>");
        ImGui::Separator();
        ImGui::TextColored(ImVec4(0.0f, 1.0f, 0.0f, 1.0f), "%.3f ms/frame (%.1f FPS)", 1000.0f / ImGui::GetIO().Framerate, ImGui::GetIO().Framerate);
        if (ImGui::BeginPopupContextWindow())
        {
            if (ImGui::MenuItem("Custom",       NULL, corner == -1)) corner = -1;
            if (ImGui::MenuItem("Top-left",     NULL, corner == 0)) corner = 0;
            if (ImGui::MenuItem("Top-right",    NULL, corner == 1)) corner = 1;
            if (ImGui::MenuItem("Bottom-left",  NULL, corner == 2)) corner = 2;
            if (ImGui::MenuItem("Bottom-right", NULL, corner == 3)) corner = 3;
            if (p_open && ImGui::MenuItem("Close")) *p_open = false;
            ImGui::EndPopup();
        }
    }
    ImGui::End();
}

